package com.spzx.product.receiver;

import com.rabbitmq.client.Channel;
import com.spzx.common.core.utils.StringUtils;
import com.spzx.common.rabbit.constant.MqConst;
import com.spzx.product.service.ISkuStockService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * @author GAX
 * @date 2025-10-11
 */

@Slf4j
@Component
public class ProductReceiver {
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ISkuStockService skuStockService;

    @SneakyThrows // lombok 自动处理异常注解
    // 接触库存锁定，恢复库存
    @RabbitListener(bindings = @QueueBinding(
            // 交换机
            exchange = @Exchange(MqConst.EXCHANGE_PRODUCT),
            // 队列
            value = @Queue(MqConst.QUEUE_UNLOCK),
            // 路由 key
            key = MqConst.ROUTING_UNLOCK
    ))
    public void unLockStock(String orderNo, Message message, Channel channel) {
        if (StringUtils.isNotBlank(orderNo)) {
            log.info("{商品服务} 监听到取消库存锁定的消息：{}", orderNo);
            // ① 幂等性处理
            String key = "sku:unlock:" + orderNo;
            Boolean flag = redisTemplate.opsForValue().setIfAbsent(key, orderNo, 5, TimeUnit.MINUTES);
            // ② 业务处理，解除库存锁定
            if (flag) {
                try {
                    skuStockService.unLockStock(orderNo);
                } catch (Exception e) {
                    // 如果出现业务异常，需要先删掉 Redis key，否则 set nx 会导致后续重试命令无效
                    redisTemplate.delete(key);
                    throw new RuntimeException(e);
                }
            }
            // ③ 手动 ack
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        }
    }
}
